package com.auto.service.impl;

import com.auto.annotation.AutoCode;
import com.auto.annotation.Column;
import com.auto.annotation.MyFunction;
import com.auto.annotation.Table;
import com.common.ArrayUtils;
import com.common.CommonUtil;
import com.common.Global;
import com.pojo.StateInfo;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 抽象类
 * 这里实现的通用的coder方法和decoder方法；getTargetPath方法基本通用，继承此抽象类的子类
 * 无需再编写这三个方法，若有个性化操作，只要重写这三个方法即可。
 * @author 陈富强
 */
public abstract class BaseCoder implements Coder{
	@Override
	public StateInfo coder(Configuration cfg, Map<String, Object> root, boolean isOverride) {
		StateInfo stateInfo = new StateInfo();
		try {
			if(!CommonUtil.isEmpty(this.getSrcPath())) {
				String fileName =
						Global.WORKSPACEPROPATH
								+this.getSrcPath()+this.getTargetPath()+"//"+root.get("className")+this.getClassTail();
				if(!isOverride) {
					File file = new File(fileName);
					if(file.exists()) {
						stateInfo.setFlag(true);
						stateInfo.setMsg("文件已存在，不进行覆盖生成!若要覆盖，请在pojo bean 注解@AutoCode(isOverride=true)");
						Logger.getLogger(this.getClass()).info("【忽略】生成文件："+this.getTargetPath()+"//"+root.get("className")+this.getClassTail()+"【"+stateInfo.getMsg()+"】");
						return stateInfo;
					}
				}
				Template template = cfg.getTemplate(this.getFtlPath(),Global.ENCODE);
				Writer out = new OutputStreamWriter(new FileOutputStream(fileName),Global.ENCODE);
				template.process(root, out);
				out.flush();
				Logger.getLogger(this.getClass()).info("生成文件："+this.getTargetPath()+"//"+root.get("className")+this.getClassTail());
				Global.Send("生成文件："+Global.WORKSPACEPROPATH+this.getSrcPath()+this.getTargetPath()+"//"+root.get("className")+this.getClassTail());
			}
		} catch (Exception e) {
			e.printStackTrace();
			stateInfo.setFlag(false);
			stateInfo.setMsg(e.getMessage());
		}
		return stateInfo;
	}
	
	@Override
	public StateInfo decoder(Configuration cfg,Map<String,Object> root,boolean isOverride) {
		StateInfo stateInfo = new StateInfo();
		try {
			if(isOverride) {
				String fileName = Global.WORKSPACEPROPATH+this.getSrcPath()+this.getTargetPath()+"//"+root.get("className")+this.getClassTail();
				File file = new File(fileName);
				if(file.exists()) {
					Global.forceDelete(file);
				}
				Logger.getLogger(this.getClass()).info("【删除】生成文件："+this.getTargetPath()+"//"+root.get("className")+this.getClassTail());
				Global.Send("【删除】生成文件："+Global.WORKSPACEPROPATH+this.getSrcPath()+this.getTargetPath()+"//"+root.get("className")+this.getClassTail());
			}
		}catch(Exception e) {
			e.printStackTrace();
			stateInfo.setFlag(false);
			stateInfo.setMsg(e.getMessage());
			Logger.getLogger(this.getClass()).error("FIELD DELETE FILE : "+this.getTargetPath()+"//"+root.get("className")+this.getClassTail()+e.getMessage());
		}
		return stateInfo;
	}
	
	public Map<String,Object> getRoot(Class<?> pojo) {
		Map<String,Object> root = new HashMap<String, Object>();
		root.put("package", this.getTargetPackage());
		root.put("beanPackage", Global.PACKAGEOFTARGETPOJO);
		root.put("daoPackage", Global.DAO_PACKAGE);
		root.put("servicePackage", Global.SERVICE_PACKAGE);
		root.put("author", Global.AUTHOR);
		root.put("className", pojo.getSimpleName());
		root.put("paramName", pojo.getSimpleName().substring(0,1).toLowerCase()+pojo.getSimpleName().substring(1));
		Table table = pojo.getAnnotation(Table.class);
		AutoCode auto = pojo.getAnnotation(AutoCode.class);
		root.put("showWay",auto.showWay().toUpperCase());
		String tableName = table.name();
		String moduleName = table.jsname();
		if(CommonUtil.isEmpty(tableName)) {
			tableName = pojo.getSimpleName();
		}
		if(CommonUtil.isEmpty(moduleName)) {
			moduleName = tableName+"服务";
		}
		root.put("moduleName",moduleName);
		//功能扩展
		MyFunction myFunction = pojo.getAnnotation(MyFunction.class);
		if(myFunction != null) {
			root.put("autoInitFromAccess", myFunction.autoInitFromAccess());
			root.put("copyLastYearData", myFunction.copyLastYearData());
			root.put("treeSort", myFunction.treeSort());
			root.put("importData", myFunction.importData());
		}else {
			root.put("autoInitFromAccess", false);
			root.put("copyLastYearData", false);
			root.put("treeSort", false);
			root.put("importData", false);
		}
		root.put("tableNameOriginal", tableName);
		if(tableName.toUpperCase().indexOf("@YEAR")!=-1) {
			root.put("yearTable", true);
		}else {
			root.put("yearTable", false);
		}
		tableName = tableName.toUpperCase().replace("@YEAR", "");
		root.put("tableName", tableName);
		Field[] fields = pojo.getDeclaredFields();
		//是否需要父类的字段。
		AutoCode ac = pojo.getAnnotation(AutoCode.class);
		if(ac.includeSupperClass()) {
			if(pojo.getSuperclass()!=null){
				Class<?> clsSup = pojo.getSuperclass();
				fields = (Field[]) ArrayUtils.addAll(fields,clsSup.getDeclaredFields());
			}
		}
		String key = null;
		String validatorProper = null;
		String keyDB = null;
		String leaf = null;
		String parentId = null;
		String parentIdType = null;
		String treecolumn = null;
		String autoGeneral = null;
		String tableJsName = table.jsname();
		StringBuffer fieldStr = new StringBuffer();//store like  id,username,age,...
		StringBuffer properStr = new StringBuffer();//store like "id","dd","ff"...
		StringBuffer jsNameStr = new StringBuffer();//store like "学生","姓名"...
		//自动插值部分。例如identity 1,1
		List<Map<String,String>> primaryList = new ArrayList<Map<String,String>>();
		List<Map<String,String>> normalList = new ArrayList<Map<String,String>>();
		List<String> treeSums = new ArrayList<String>();
		for(Field field : fields) {
			Column column = field.getAnnotation(Column.class);
			if(column == null) {
				continue;
			}
			String dbcname = CommonUtil.isEmpty(column.name())?field.getName():column.name();
			String proper = field.getName();
			String flag = column.flag();
			if(column.treeId() || flag.toUpperCase().equals("PRIMARY")) {
				key = proper;
				keyDB = dbcname;
			}
			if(column.treeleaf()) {
				leaf = proper;
			}
			if(column.treeparentId()) {
				parentId = proper;
				parentIdType = field.getType().getSimpleName().toUpperCase();
			}
			if(column.treecolumn()) {
				treecolumn = proper;
			}
			if(column.treeSum()) {
				treeSums.add(proper);
				
			}
			if(column.autoGenneral()) {
				autoGeneral = dbcname;
			}
			String type = CommonUtil.isEmpty(column.type())?"VARCHAR":column.type().toUpperCase();
			if(type.indexOf("VARCHAR")!=-1) {
				type="VARCHAR";
			}else if(type.indexOf("INT")!=-1) {
				type="INTEGER";
			}else if(type.indexOf("DECIMAL")!=-1) {
				type="DECIMAL";
			}
			if(fieldStr.length()==0) {
				fieldStr.append(dbcname);
			}else {
				fieldStr.append(","+dbcname);
			}
			if(properStr.length()==0) {
				properStr.append("\""+proper+"\"");
				jsNameStr.append("\""+column.jsname()+"\"");
			}else {
				properStr.append(",\""+proper+"\"");
				jsNameStr.append(",\""+column.jsname()+"\"");
			}
			if(proper.toUpperCase().equals("COMPANYID")) {
				root.put("companyidMethod","set"+proper.substring(0,1).toUpperCase()+proper.substring(1));
			}else if(proper.toUpperCase().equals("THEYEAR")) {
				root.put("theyearMethod","set"+proper.substring(0,1).toUpperCase()+proper.substring(1));
			}else if(proper.toUpperCase().contentEquals("THEMONTH")) {
				root.put("themonthMethod","set"+proper.substring(0,1).toUpperCase()+proper.substring(1));
			}
			if(column.jsValidator()) {
				validatorProper = proper;
			}
			Map<String,String> map = new HashMap<String, String>();
			map.put("dbcname", dbcname);
			map.put("proper", proper);
			if("BOOLEAN".equals(field.getType().getSimpleName().toUpperCase())){
				map.put("getMethod", "is"+proper.substring(0,1).toUpperCase()+proper.substring(1));
			}else {
				map.put("getMethod", "get"+proper.substring(0,1).toUpperCase()+proper.substring(1));
			}
			map.put("setMethod", "set"+proper.substring(0,1).toUpperCase()+proper.substring(1));
			map.put("type", type);
			
			if(column.oth().toUpperCase().equals("IDENTITY(1,1)")) {
				primaryList.add(map);
			}else {
				normalList.add(map);
			}
		}
		if(treeSums.size() != 0) {
			root.put("treeSums", treeSums);
		}
		if(autoGeneral!= null) {
			root.put("autoGeneral", autoGeneral);
		}
		root.put("primaryList", primaryList);
		root.put("normalList", normalList);
		root.put("columnFields",fieldStr.toString());
		root.put("treecolumn", treecolumn);
		root.put("properStr", properStr.toString());
		root.put("jsNameStr", jsNameStr.toString());
		root.put("tableJsName", tableJsName);
		root.put("keyDB", keyDB);
		root.put("key", key);
		root.put("validatorProper", validatorProper);
		root.put("getKey", "get"+key.substring(0,1).toUpperCase()+key.substring(1));
		root.put("setKey", "set"+key.substring(0,1).toUpperCase()+key.substring(1));
		if(leaf != null) {
			root.put("leaf", leaf);
			root.put("getLeaf", "get"+leaf.substring(0,1).toUpperCase()+leaf.substring(1));
			root.put("setLeaf", "set"+leaf.substring(0,1).toUpperCase()+leaf.substring(1));
		}
		if(parentId != null) {
			root.put("parentId", parentId);
			root.put("parentIdType", parentIdType);
			root.put("getParentId", "get"+parentId.substring(0,1).toUpperCase()+parentId.substring(1));
			root.put("setParentId", "set"+parentId.substring(0,1).toUpperCase()+parentId.substring(1));
		}

		return root;
	}
	
	public String getTargetPath() {
		String p = this.getTargetPackage();
		if(CommonUtil.isEmpty(p)) {
			return p;
		}else {
			String[] ps = p.split("\\.");
			if(ps == null || ps.length == 0) {
				ps = new String[1];
				ps[0] = p;
			}
			StringBuffer targetPath = new StringBuffer();
			for(String t : ps) {
				targetPath.append("//").append(t);
			}
			return targetPath.toString();
		}
	}
}
